package com.jack.netty.tcp.client;

import com.jack.netty.log.LoggerManager;
import com.jack.netty.message.Ping;
import com.jack.netty.message.Pong;
import com.jack.netty.message.UserMsg;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;

/**
 * Created by jack on 15/9/26.
 */
public class TLVClientHandler extends ChannelHandlerAdapter{

    private String attributeKeyPingCount = "attributeKeyPingCount";
    private final AttributeKey<Integer> pingKey = AttributeKey.valueOf(attributeKeyPingCount);

    private TLVClientListener tlvClientListener = null;
    private ChannelHandlerContext channelHandlerContext = null;

    private int failHeartCount = 5;

    private boolean connectedFlag = false;

    public TLVClientHandler(TLVClientListener tlvClientListener){
        this.tlvClientListener = tlvClientListener;
        if(this.tlvClientListener == null){
            LoggerManager.getInstance().getiLogger().warn(getClass(),"未设置消息监听器 TLVClientListener!");
        }
    }


    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if(evt instanceof IdleStateEvent){
            IdleStateEvent idleStateEvent = (IdleStateEvent)evt;
            if(idleStateEvent.state() == IdleState.READER_IDLE){
                ctx.writeAndFlush(Ping.getInstance());

                //处理ping的计数增加
                Attribute<Integer> pingAttr = ctx.attr(pingKey);
                Integer pingCount = pingAttr.get();
                if(pingCount == null){
                    pingCount = 1;
                }else{
                    if(pingCount > failHeartCount){
                        //大量心跳木有回应，判断服务器离线,关闭连接
                        LoggerManager.getInstance().getiLogger().info(getClass(),"感知到服务无响应");
                        ctx.channel().close();
                    }else{
                        pingCount += 1;
                    }
                }
                LoggerManager.getInstance().getiLogger().debug(getClass(),ctx.channel().id().asLongText() + "服务器 pingCount:" + pingCount);
                pingAttr.set(pingCount);

            }else if(idleStateEvent.state() == IdleState.WRITER_IDLE){
                //
            }
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        LoggerManager.getInstance().getiLogger().info(getClass(),"连接成功");
        setConnectedFlag(true);
        channelHandlerContext = ctx;
        tlvClientListener.onConnect(ctx.channel().id().asLongText());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        LoggerManager.getInstance().getiLogger().info(getClass(),"连接断开");
        setConnectedFlag(false);
        //channelHandlerContext = null;
        tlvClientListener.onDisconnect(ctx.channel().id().asLongText());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //处理ping的计数递减
        Attribute<Integer> pingAttr = ctx.attr(pingKey);
        Integer pingCount = pingAttr.get();
        if(pingCount == null){
            pingCount = new Integer(0);
        }else{
            pingCount = 0;
        }
        pingAttr.set(pingCount);

        //处理消息
        if(msg instanceof Ping){
            LoggerManager.getInstance().getiLogger().debug(getClass(),"收到服务器:"+ctx.channel().id().asLongText()+" ping");
            //回应ping
            ctx.writeAndFlush(Pong.getInstance());

        }else if (msg instanceof Pong) {

            LoggerManager.getInstance().getiLogger().debug(getClass(),"收到服务器:"+ctx.channel().id().asLongText()+" pong");

        }else if(msg instanceof UserMsg){

            UserMsg um = (UserMsg)msg;
            //处理消息
            String msgStr = new String(um.getData(),"utf8");
            LoggerManager.getInstance().getiLogger().info(getClass(),"收到服务器:" + ctx.channel().id().asLongText() + " 的消息:" + msgStr);

            try {
                tlvClientListener.onMessage(ctx.channel().id().asLongText(),msgStr);
            }catch (Exception e){
                LoggerManager.getInstance().getiLogger().error(getClass(),"处理消息错误:"+e.getMessage());
            }
        }else{
            LoggerManager.getInstance().getiLogger().error(getClass(),"收到服务器:" + ctx.channel().id().asLongText() + " 未定义的消息:" + msg.toString());
        }
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        LoggerManager.getInstance().getiLogger().error(getClass(),"连接错误:" + cause.getMessage());
        ctx.channel().close();
    }

    public ChannelHandlerContext getChannelHandlerContext() {
        return channelHandlerContext;
    }

    public String getServerId(){
        if(channelHandlerContext != null){
            return channelHandlerContext.channel().id().asLongText();
        }

        return System.currentTimeMillis()+"";
    }

    public boolean isConnectedFlag() {
        return connectedFlag;
    }

    public void setConnectedFlag(boolean connectedFlag) {
        this.connectedFlag = connectedFlag;
    }

}
